﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using nGSO.KnapsackProblem;
using nGSO;
using System.Configuration;

namespace nGSO.Tests
{
	[TestFixture]
	public class GsoKpTests
	{
		#region gso config
		
		private int _luceferinInitialValue = 5;
		private double _decisionRange = 3;
		private double _updateDecisionRange = 0.08;
		private int _neighbourhoodThreshold = 5;
		private double _stepSize = 0.03;
		private double _updateLuceferingValue = 0.6;
		private double _dissipationOfLuceferin = 0.4;
		
		#endregion

		[Test(Description = "Third test data from publication KP-AGSO"), Repeat(50)]
		public void CalculateThirdTestData()
		{
			int _iterations = 500;
			int _glowworms = 100;
			int optimalCost = 2975;

			GsoConfig config = new GsoConfig(_updateDecisionRange, _luceferinInitialValue, _dissipationOfLuceferin, _glowworms,
				_decisionRange, _iterations, _neighbourhoodThreshold, _updateLuceferingValue, _stepSize, 1, new MaximumProbabilitySelector());

			//config.AfterAgentMoveExtensions.Add(new NeighborhoodRangeExtender() { Enabled=true });

            KpConfigElement kpProblemConfig = new KpConfigElement
			{
				EncodedCosts = "220,208,198,192,180,180,165,162,160,158,155,130,125,122,120,118,115,110,105,101,100,100,98,96,95,90,88,82,80,77,75,73,72,70,69,66,65,63,60,58,56,50,30,20,15,10,8,5,3,1",
				MaxCapacity = 1000,
				EncodedWeights = "80,82,85,70,72,70,66,50,55,25,50,55,40,48,50,32,22,60,30,32,40,38,35,32,25,28,30,22,25,30,45,30,60,50,20,65,20,25,30,10,20,25,15,10,10,10,4,4,2,1"
			};
			config.Dims = kpProblemConfig.Dims;

			RunTestData(config, kpProblemConfig, 1, optimalCost);
		}


		[Test(Description = "Second test data from publication KP-AGSO"), Repeat(50)]
		public void CalculateSecondTestData()
		{
			int _iterations = 300;
			int _glowworms = 50;
			int optimalCost = 1037;

			GsoConfig config = new GsoConfig(_updateDecisionRange, _luceferinInitialValue, _dissipationOfLuceferin, _glowworms,
				_decisionRange, _iterations, _neighbourhoodThreshold, _updateLuceferingValue, _stepSize, 1, new MaximumProbabilitySelector());

			//config.AfterAgentMoveExtensions.Add(new NeighborhoodRangeExtender() { Enabled=true });

            KpConfigElement kpProblemConfig = new KpConfigElement()
			{
				EncodedCosts = "92, 4, 43, 83, 84, 68, 92, 82, 6, 44, 32, 18, 56, 83, 25, 96, 70, 48, 14, 58",
				MaxCapacity = 878,
				EncodedWeights = "44, 46, 90, 72, 91, 40, 75, 35, 8, 54, 78, 40, 77, 15, 61, 17, 75, 29, 75, 63"
			};
			config.Dims = kpProblemConfig.Dims;

			RunTestData(config, kpProblemConfig, 1, optimalCost);
		}


		[Test(Description="First test data from publication KP-AGSO"), Repeat(30)]
		public void CalculateFirstTestData()
		{
			int _iterations = 100;
			int _glowworms = 30;
			int optimalCost = 295;
			GsoConfig config = new GsoConfig(_updateDecisionRange, _luceferinInitialValue, _dissipationOfLuceferin, _glowworms,
				_decisionRange, _iterations, _neighbourhoodThreshold, _updateLuceferingValue, _stepSize, 1, new MaximumProbabilitySelector());

			//config.AfterAgentMoveExtensions.Add(new NeighborhoodRangeExtender() { Enabled=true });

            KpConfigElement kpProblemConfig = new KpConfigElement
			{
				EncodedCosts ="55, 10, 47, 5, 4, 50, 8, 61, 85, 87",
				MaxCapacity = 269,
				EncodedWeights = "95, 4, 60, 32, 23, 72, 80, 62, 65, 46"
			};
			config.Dims = kpProblemConfig.Dims;

			RunTestData(config, kpProblemConfig, 1, optimalCost);
		}

		private void RunTestData(GsoConfig config, KpConfigElement kpProblemConfig, int runTimes, int optimalCost)
		{
			List<Agent> solutions = new List<Agent>();

			for (int i = 0; i < runTimes; i++)
			{
				solutions.AddRange(GetSolution(config, kpProblemConfig));
			}

			bool foundSolution = false;

			foreach (var item in solutions)
			{
				foundSolution = CheckSolution(kpProblemConfig, item, optimalCost);
				if (foundSolution)
				{
					break;
				}
			}
		}

		private bool CheckSolution(KpConfigElement kpConfig, Agent solution, int optimalCost)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append("Solution ");

			var initHistiory = solution.History[0].Loc;
			double totalCost = 0;
			double totalWeight = 0;

			for (int i = 0; i < kpConfig.Dims; i++)
			{
				totalCost += initHistiory[i] * kpConfig.Costs[i];
				totalWeight += initHistiory[i] * kpConfig.Weights[i];
			}

			sb.AppendLine(string.Format(" Cost:{0} Weight:{1}", totalCost, totalWeight));

			bool res = (totalWeight <= kpConfig.MaxCapacity) && (totalCost >= optimalCost);

			if (res)
				Console.WriteLine(string.Format("Found solution W {0} C {1}", totalWeight, totalCost));
			
			return res;
		}

		public List<Agent> GetSolution(GsoConfig config, KpConfigElement kpConfig)
		{
			
			KPFitnessCalulator calc = new KPFitnessCalulator(kpConfig);

			GsoConfig.FitnessFunPointer = calc;

			KPSearchSpace space = new KPSearchSpace(config, kpConfig);

			
			GsoEngine engine = new GsoEngine(space, new DefaultNeighboursLocalizator(), config);

			var resultSpace = engine.StartGSOSolving();

			return resultSpace.Agents;
		}
	}
}
